home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / pmode / pmode30b / pmode.doc < prev    next >
Text File  |  1994-05-31  |  88KB  |  2,049 lines

  1.  
  2.   This is the documentation for PMODE v3.0 DPMI/VCPI/XMS/raw protected mode
  3. interface kernel. Copyright (c) 1994, Tran (a.k.a. Thomas Pytel). PMODE is
  4. publicly available and is not confidential or proprietary. I, Thomas Pytel,
  5. reserve all rights to the source code. However, feel free to use or distribute
  6. it in any manner you wish. All I ask, if you use this code in some production,
  7. is credits for it.
  8.  
  9. ------------------------------------------------------------------------------
  10. Contents:
  11. ---------
  12.  
  13.   0 - Introduction
  14.       0.0 - Disclaimer
  15.       0.1 - Description
  16.   1 - Overview
  17.       1.0 - Initialization and termination
  18.       1.1 - Segments, selectors, and descriptors
  19.       1.2 - Stacks and mode switching
  20.       1.3 - Interrupts
  21.       1.4 - Real mode callbacks
  22.       1.5 - PMODE specifics
  23.   2 - Functions
  24.       2.0 - Function 0000h - Allocate Descriptors
  25.       2.1 - Function 0001h - Free Descriptor
  26.       2.2 - Function 0003h - Get Selector Increment Value
  27.       2.3 - Function 0006h - Get Segment Base Address
  28.       2.4 - Function 0007h - Set Segment Base Address
  29.       2.5 - Function 0008h - Set Segment Limit
  30.       2.6 - Function 0009h - Set Descriptor Access Rights
  31.       2.7 - Function 000Ah - Create Alias Descriptor
  32.       2.8 - Function 000Bh - Get Descriptor
  33.       2.9 - Function 000Ch - Set Descriptor
  34.       2.10 - Function 000Eh - Get Multiple Descriptors
  35.       2.11 - Function 000Fh - Set Multiple Descriptors
  36.       2.12 - Function 0200h - Get Real Mode Interrupt Vector
  37.       2.13 - Function 0201h - Set Real Mode Interrupt Vector
  38.       2.14 - Function 0204h - Get Protected Mode Interrupt Vector
  39.       2.15 - Function 0205h - Set Protected Mode Interrupt Vector
  40.       2.16 - Function 0300h - Simulate Real Mode Interrupt
  41.       2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame
  42.       2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame
  43.       2.19 - Function 0303h - Allocate Real Mode Callback Address
  44.       2.20 - Function 0304h - Free Real Mode Callback Address
  45.       2.21 - Function 0305h - Get State Save/Restore Addresses
  46.       2.22 - Function 0306h - Get Raw Mode Switch Addresses
  47.       2.23 - Function 0400h - Get Version
  48.       2.24 - Function 0500h - Get Free Memory Information
  49.       2.25 - Function 0501h - Allocate Memory Block
  50.       2.26 - Function 0502h - Free Memory Block
  51.       2.27 - Function 0503h - Resize Memory Block
  52.       2.28 - Function 050Ah - Get Memory Block Size and Base
  53.       2.29 - Function 0900h - Get and Disable Virtual Interrupt State
  54.       2.30 - Function 0901h - Get and Enable Virtual Interrupt State
  55.       2.31 - Function 0902h - Get Virtual Interrupt State
  56.   3 - Miscellaneous
  57.       3.0 - Glossary
  58.       3.1 - Differences among modes
  59.       3.2 - Notes
  60.       3.3 - Final word
  61.  
  62. ------------------------------------------------------------------------------
  63. 0 - Introduction:
  64. -----------------
  65.  
  66.   This document will not attempt to explain the workings of protected mode. If
  67. you are new to protected mode coding, I suggest you get yourself a good book.
  68. I also suggest you get your hands on some good DPMI documentation as a
  69. reference and background for understanding PMODE. This document is only
  70. intended to explain the workings of PMODE for the purpose of using it directly
  71. or for writing a shell or high level language interface.
  72.  
  73. 0.0 Disclaimer:
  74. ---------------
  75.  
  76. Legal:
  77.  
  78.   I exclude any and all implied warranties, including warranties of
  79. merchantability and fitness for a particular purpose. I make no warranty or
  80. representation, either express or implied, with respect to this source code,
  81. its quality, performance, merchantability, or fitness for a particular
  82. purpose. I shall have no liability for special, incidental or consequential
  83. damages arising out of or resulting from the use or modification of this
  84. source code.
  85.  
  86. English:
  87.  
  88.   If you fuck up, its your own problem.
  89.  
  90. 0.1 Description:
  91. ----------------
  92.  
  93.   PMODE v3.0 is basically a DOS extender. It allows DOS programs to run in
  94. full protected mode. PMODE will take care of all the system details, the
  95. descriptor tables, extended memory management, interrupts, etc... It does not
  96. matter what kind of system is already in place. DPMI, VCPI, XMS, and a clean
  97. system will all be handled appropriately. If DPMI is in place, PMODE will do
  98. basically nothing, and your code will be talking directly to the DPMI host.
  99. But if it is not, PMODE will provide a subset of DPMI functionality to your
  100. code. It is slightly annoying that most of the DPMI interface uses pairs of
  101. 16bit registers for 32bit values. This goes back to the 80286 support of DPMI.
  102.  
  103.   Code using PMODE can set up its own descriptors. It can run across real
  104. mode, 16bit protected mode, and 32bit protected mode. Full extended memory
  105. management is provided. Blocks of extended memory can be allocated, resized,
  106. and freed. PMODE does not manage low memory, Your code is responsible for the
  107. memory below the 1M boundary. The PMODE kernel is well suited for a shell to
  108. extend its functionality. A shell to provide extended or simplified services
  109. to assembly or high level code.
  110.  
  111.   I wrote PMODE with attention to speed. Wherever I could control it, I tried
  112. to ensure that code using PMODE would run as fast as possible. I also tried to
  113. make sure PMODE is very stable. Under DPMI, your code is a slave to the DPMI
  114. host's whims. Almost definately running at CPL 3, which makes it quite slow.
  115. There is nothing I can do about that. Well, locating and messing with the DPMI
  116. host's system tables might not be too hard, but too unpredictable. Running in
  117. protected mode at CPL 3 is better than real mode CPL 3, because you can avoid
  118. loading segment registers very often (which is slow) by setting up flat
  119. memory. However, if DPMI is not present, you can be sure your code will be
  120. running as fast as it possibly can. Under a VCPI, XMS, or raw system, PMODE
  121. will run your code at CPL 0. There are no I/O permission bitmap checks on port
  122. accesses or task switching. Under an XMS or raw system, real mode calls are
  123. executed in actual real mode rather than the slower V86 mode, which is
  124. actually protected mode at CPL 3. Under VCPI, real mode calls are executed in
  125. V86 mode, which is what the VCPI server normally runs DOS in. Also, under
  126. VCPI, paging is enabled. It is a minor speed degredation factor, but one that
  127. is avoided under XMS or raw.
  128.  
  129.   I've been coding 386 protected mode systems for a couple of years now. I
  130. tried to make PMODE as clean as possible. But it was coded from scratch.
  131. Though I tested it extensively, there is unfortunately always the possibility
  132. of a bug. I am pretty confident it is clean though, because I went over EVERY
  133. line of code when finally done with it. I also plugged it into some old
  134. programs using a previous version of PMODE, which did well to help me find a
  135. few bugs.
  136.  
  137. ------------------------------------------------------------------------------
  138. 1 - Overview:
  139. -------------
  140.  
  141.   I adopted the DPMI interface for PMODE to make code that works with PMODE
  142. very portable to other extenders. Only a subset of DPMI is supported, both to
  143. keep the size of the kernel down, and because I am lazy (the latter being the
  144. more important factor). The interface to PMODE is INT 31h in protected mode.
  145. Functions are available for descriptors, interrupt vectors, extended memory,
  146. real mode callbacks, and calling real mode interrupts and procedures. PMODE
  147. works as a subset of DPMI 1.0 rather than DPMI 0.9. This means that error
  148. codes are returned from unsuccessful function calls, and some functions are
  149. available that are not available under DPMI 0.9. Note though, that if the
  150. system is already under DPMI 0.9, PMODE code is not active, so error codes
  151. will not be returned and only DPMI 0.9 functions will be available.
  152.  
  153. 1.0 - Initialization and termination:
  154. -------------------------------------
  155.  
  156.   There are only two functions immediately callable in PMODE. They are
  157. _pm_info and _pm_init. _pm_info returns some information about the current
  158. type of system and the low memory requirements for protected mode. No matter
  159. what the system, DPMI, VCPI, XMS, or raw, a low memory buffer is required for
  160. protected mode operation. The size of this buffer is returned from _pm_info.
  161. Your code is responsible for providing that buffer to _pm_init.
  162.  
  163.   _pm_init switches the system into protected mode. If DPMI is in place, all
  164. that is done is a switch into 32bit protected mode. If the DPMI host does not
  165. support 32bit protected mode, _pm_init will return an error. 32bit protected
  166. mode does not necessarily mean your code has to run in a 32bit segment with
  167. default 32bit instructions. It just means that it is possible. Since DPMI is
  168. defined for 80286 computers, and you might even find DPMI that is capable of
  169. 32bit protected mode refusing this request on a 386 system.
  170.  
  171.   _pm_init will return with the carry flag set and an error code in AX if an
  172. error ocurred while trying to switch into protected mode. If the switch to
  173. protected mode was successful, the carry flag will be clear, and the system
  174. will be in protected mode. The CS segment register will have been converted
  175. to a protected mode selector corresponding to a descriptor mapping the same
  176. memory as it did in real mode. Likewise, the DS and SS segment registers will
  177. be converted to selectors. If DS and SS were equal before the call to
  178. _pm_init, the same selector may be returned in both. ES will contain a
  179. selector for your program's PSP. The environment segment at PSP:2ch will also
  180. be converted to a selector if it was a non-zero value before the call to
  181. _pm_init. FS and GS will be returned as 0 (NULL selector). Your code will now
  182. be running in a 16bit protected mode code segment, with full access to the
  183. protected mode INT 31h functions. If the system is DPMI, this is the last your
  184. code will have talked to PMODE, and from now on, will be using the DPMI host
  185. directly.
  186.  
  187. Both functions are FAR, and the full calling format is as follows:
  188.  
  189. ) _pm_info - Get protected mode info:
  190.   In:
  191.     None
  192.   Out:
  193.     AX - return code:
  194.       0000h - successful
  195.       0001h - no 80386+ detected
  196.       0002h - system already in protected mode and no VCPI or DPMI found
  197.       0003h - DPMI - host is not 32bit
  198.     CF - set on error, if no error:
  199.       BX - number of paragraphs needed for protected mode data (may be 0)
  200.       CL - processor type:
  201.     03h - 80386
  202.     04h - 80486
  203.     05h - 80586
  204.     06h-FFh - reserved for future use
  205.       CH - protected mode type:
  206.     00h - raw
  207.     01h - XMS
  208.     02h - VCPI
  209.     03h - DPMI
  210.  
  211. ) _pm_init - Initialize protected mode:
  212.   In:
  213.     ES - real mode segment for protected mode data (ignored if not needed)
  214.   Out:
  215.     AX - return code:
  216.       0000h - successful
  217.       0001h - no 80386+ detected
  218.       0002h - system already in protected mode and no VCPI or DPMI found
  219.       0003h - DPMI - host is not 32bit
  220.       0004h - could not enable A20 gate
  221.       0005h - DPMI - could not enter 32bit protected mode
  222.       0006h - DPMI - could not allocate needed selectors
  223.     CF - set on error, if no error:
  224.       ESP - high word clear
  225.       CS - 16bit selector for real mode CS with limit of 64k
  226.       SS - 32bit selector for real mode SS with limit of 64k
  227.       DS - 32bit selector for real mode DS with limit of 64k
  228.       ES - 32bit selector for PSP with limit of 100h
  229.       FS - 0 (NULL selector)
  230.       GS - 0 (NULL selector)
  231.  
  232.   The CS, DS, and SS selectors returned from _pm_init can be modified or
  233. freed by your code. The PSP selector and the converted environment selector in
  234. the PSP may not be. There is a special case when the CS selector returned from
  235. _pm_init may not be freed or modified. That is when the FAR CALL to _pm_init
  236. came from the PMODE_TEXT segment. In this case, PMODE will return its own code
  237. selector which maps PMODE_TEXT. This is just a minor optimization provided for
  238. any shell that has its code in PMODE_TEXT to save a descriptor.
  239.  
  240.   To terminate under PMODE, your code must issue an INT 21h function 4ch in
  241. protected mode. Just like in real mode, AL is the return code. Your code
  242. should only terminate from the main stream of execution. That is, do not try
  243. to quit from a protected mode IRQ handler or a real mode callback. Before
  244. termination, your code has the following responsibilities:
  245.  
  246. ) Restore any real mode interrupt vectors which were hooked.
  247.  
  248. ) Free any extended memory blocks that were allocated.
  249.  
  250. 1.1 - Segments, selectors, and descriptors:
  251. -------------------------------------------
  252.  
  253.   As you know (I hope), in protected mode, selectors are used in place of
  254. actual segment values in segment registers. Selectors are basically indexes
  255. into system tables which contain all the information about segments in
  256. descriptors. You can think of selectors as handles to segments. They are
  257. independent of the actual location and size of the segment in memory.
  258.  
  259.   Under PMODE, your code can allocate its own selectors and descriptors. You
  260. can set up code segments, data segments, and your own stack segments. These
  261. segments can be either 16bit, 32bit, or a mix. The best use of the flexibility
  262. of protected mode is to set up very large segments, in effect, eliminating the
  263. need for segmentation. You can set up a code descriptor, and set its size to
  264. 4G. Then a data descriptor of that same size and with the same base address.
  265. When all memory is addressable from a single segment, there is little need for
  266. other segments. But they are available, possibly for code modules to be loaded
  267. from disk into seperate segments.
  268.  
  269.   After allocating a descriptor, you code can set it up in one shot, with
  270. Set Descriptor function (000ch). Or you can set the base address, limit, and
  271. access rights/type seperately. You can also allocate a descriptor and have it
  272. automatically set to the same base address and size as another descriptor
  273. using the Create Alias Descriptor function (000ah). You code can also read a
  274. whole descriptor or base address of a descriptor. There is no Get Segment
  275. Limit function because the LSL instruction performs that function. The LAR
  276. instruction returns the access rights/type of a descriptor.
  277.  
  278.   Technically, it is possible for DPMI to deny requests to set up very large
  279. segments for protection reasons. But no DPMI host that I know of does this.
  280. They all do protection at the paging level. DPMI 1.0 specifies a function
  281. that returns an absolute ceiling for large segments. Allowing for flat memory,
  282. but falling short of the full 4G linear address range. I would not worry about
  283. this. If DPMI 1.0 hosts started to deny requests to set segment sizes to 4G,
  284. many protected mode extended programs would cease to function.
  285.  
  286.   When setting up a data descriptor which will be used as a stack segment, be
  287. aware that the B bit will determine whether PUSHes and POPs on that stack use
  288. SP or ESP as the top of stack pointer. However, even if you use a stack with
  289. the B bit clear (using SP), ESP should still be the top of stack pointer.
  290. Which means that when using a 16bit stack segment, the high word of ESP MUST
  291. be clear.
  292.  
  293. 1.2 - Stacks and mode switching:
  294. --------------------------------
  295.  
  296.   Within your main stream of execution, your code can set up its own stack.
  297. But there are times when a stack is provided to your code and your code should
  298. stay on that stack. At those times, your code may switch stacks during
  299. processing, but should return on the same stack it was called. This is during
  300. servicing of hardware interrupts or real mode callbacks in protected mode.
  301.  
  302.   Switching between protected mode and real mode can be accomplished in one of
  303. many ways. In protected mode, the default IRQ handlers switch to real mode to
  304. execute the real mode handler for the specific IRQ that was called. A software
  305. INT instruction in protected mode is also, by default, sent to on to real mode
  306. for processing. There are three specific functions which allow you to call
  307. real mode interrupts and procedures in a much more structured manner. There
  308. are real mode callbacks. These are basically addresses in real mode which,
  309. when called in real mode, transfer control to protected mode routines defined
  310. by your code. And finally, there is raw mode switching. Your code can obtain
  311. the addresses of a real mode routine which will switch the system into
  312. protected mode, and a protected mode routine which will switch the system into
  313. real mode. This is the lowest level, and quickest, method of switching modes.
  314. IRQ and INT redirection is discussed later, as are real mode callbacks.
  315.  
  316.   The INT 31h functions 0300h, 0301h, and 0302h allow your code to call real
  317. mode interrupts of FAR routines. Since protected mode selectors are not valid
  318. in real mode, your must pass the values to load into the segment registers in
  319. real mode, for the interrupt or routine, in a memory structure. This structure
  320. also contains the general registers as you want to pass them to real mode.
  321. Using these INT 31h functions, you can specify a portion of data from the
  322. protected mode stack to be put on the real mode stack for the interrupt or
  323. procedure call. You also do not have to provide a real mode stack. If you set
  324. the SS and SP fields in the register structure to 0, PMODE will provide a real
  325. mode stack for the real mode call. If you prefer, however, you can provide the
  326. stack yourself. Upon return from the real mode call, the register structure
  327. will contain the values that were passed back in the registers from the real
  328. mode interrupt handler or procedure. The CS, IP, SS, and SP fields will remain
  329. unmodified though.
  330.  
  331.   Using the raw mode switching routines is the fastest way to switch between
  332. modes. However, if these functions are to be used, special measures must be
  333. taken to preserve the state of the system. If using raw mode switching, you
  334. must use the state save/restore fuctions whose addresses you can obtain with
  335. INT 31h function 0305h. The state is saved in a buffer you provide. The stack
  336. is a good place for this buffer. Some example code is in order:
  337.  
  338.  
  339. buffersize      dd      ?               ; size of state buffer
  340.  
  341. pmstate         df      ?               ; selector:offset of state routine
  342. pmtorm          df      ?               ; selector:offset of switch routine
  343.  
  344. rmstate         dd      ?               ; segment:offset of state routine
  345. rmtopm          dd      ?               ; segment:offset of switch routine
  346.  
  347. ; this code gets and stores the addresses of the various routines
  348.         mov ax,305h                     ; get addresses of state save/restore
  349.         int 31h                         ;  routines
  350.  
  351.         movzx eax,ax                    ; zero high word of EAX
  352.         mov buffersize,eax              ; size of state buffer
  353.         mov word ptr rmstate[0],cx      ; offset of real mode state routine
  354.         mov word ptr rmstate[2],bx      ; segment of real mode state routine
  355.         mov dword ptr pmstate[0],edi    ; offset of protected mode routine
  356.         mov word ptr pmstate[4],si      ; selector of protected mode routine
  357.  
  358.         mov ax,306h                     ; get addresses of mode switch
  359.         int 31h                         ;  routines
  360.  
  361.         mov word ptr rmtopm[0],cx       ; offset of real mode switch routine
  362.         mov word ptr rmtopm[2],bx       ; segment of real mode switch routine
  363.         mov dword ptr pmtorm[0],edi     ; offset of protected mode routine
  364.         mov word ptr pmtorm[4],si       ; selector of protected mode routine
  365.  
  366. ; this code saves the state and jumps to real mode
  367.         sub esp,buffersize              ; allocate buffer space on stack
  368.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  369.         mov ax,ss
  370.         mov es,ax
  371.         xor al,al                       ; set AL = 0, save state
  372.         call pmstate                    ; save state
  373.  
  374.         mov ax,real_mode_DS_value       ; set values for real mode registers
  375.         mov cx,real_mode_ES_value
  376.         mov dx,real_mode_SS_value
  377.         mov bx,real_mode_SP_value
  378.         mov si,real_mode_CS_value
  379.         mov di,real_mode_IP_value
  380.         jmp pmtorm                      ; switch to real mode
  381.  
  382. ; this would restore the state after a return from real mode
  383.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  384.         mov ax,ss
  385.         mov es,ax
  386.         mov al,1                        ; set AL = 1, restore state
  387.         call pmstate                    ; restore state
  388.         add esp,buffersize              ; discard stack buffer space
  389.  
  390.   Real mode code to save/restore the state and call protected mode would be
  391. similar, except that EBX would be used to pass a value for ESP, and EDI would
  392. be used to pass EIP rather than IP in switching modes. Also, ES:DI would be
  393. used as the state buffer rather than ES:EDI.
  394.  
  395. 1.3 - Interrupts:
  396. -----------------
  397.  
  398.   When protected mode is first entered, all interrupts except those providing
  399. DPMI functionality are directed to a handler which will pass them on to real
  400. mode. That is, a software INT instruction executed by your code in protected
  401. mode will cause the CPU to be switched to real mode and the interrupt will be
  402. re-issued in real mode. After the interrupt handler returns, the system will
  403. be switched back to protected mode. All general registers (EAX, EBX, ECX, EDX,
  404. ESI, EDI, and EBP) in protected mode are passed on to the real mode handler,
  405. and the general registers and flags are passed back from real mode. The
  406. segment registers are not passed on to real mode since segment registers have
  407. different meanings in protected mode and real mode. This means that you can
  408. call simple interrupt routines which do not require values in segment
  409. registers, such as the keyboard BIOS function 0 to read a character from the
  410. keyboard, by just setting AH to 0 and issuing an INT 16h in protected mode. If
  411. you need to pass segment registers to a real mode interrupt handler, you must
  412. use the INT 31h function 0300h.
  413.  
  414.   IRQs are likewise passed on to real mode. PMODE will not, for the sake of a
  415. little speed increase, pass any registers to or from a real mode IRQ handler.
  416. A real DPMI host probably will pass the general registers just as it would for
  417. a software INT instruction. You may hook a protected mode interrupt vector for
  418. any interrupt, 0-0ffh, and process the interrupt entirely in protected mode if
  419. you wish. Or you can do some processing in protected mode, then chain to the
  420. real mode handler by passing control to the previous handler for the interrupt
  421. your code hooked.
  422.  
  423.   PMODE will provide a real mode stack for both the software INT redirection
  424. and the hardware IRQ redirection to real mode. If a real mode stack is
  425. unavailable because of too many nested calls to real mode, the PC speaker will
  426. be turned on and the machine will be hung. I prefer this to clunky exception
  427. code messing up my nice and pretty extender.
  428.  
  429.   In protected mode, when interrupt handlers are called, the interrupt flag is
  430. not disabled like it is in real mode. This is done only for IRQs and
  431. interrupts 0-7. Handlers for all other interrupts in protected mode must not
  432. assume the interrupt flag has been cleared for them. If they need interrupts
  433. disabled, they must do it themselves.
  434.  
  435.   Under DPMI, the interrupt flag may need to be virtualized. I will spare you
  436. a long explanation because any good DPMI text will give that to you. But I
  437. will give you some rules:
  438.  
  439. ) You must not assume anything about instructions that would normally affect
  440.   the interrupt flag. Instructions like POPF and IRETD may have no effect on
  441.   the current status of the interrupt flag. Also, PUSHF or an INT may not
  442.   store the interrupt flag correctly, so do not trust them to get information
  443.   on the interrupt flag.
  444.  
  445. ) The only things you can be sure will affect the interrupt flag are CLI, STI,
  446.   and INT 31h functions 0900h and 0901h.
  447.  
  448. ) If you need to learn the current status of the interrupt flag, you must use
  449.   one of the INT 31h functions, 0900h to clear and get the status of the
  450.   interrupt flag, 0901h to set and get the status of the flag, or 0902h which
  451.   simply returns the current value of the interrupt flag.
  452.  
  453. ) Since IRETD may not affect the interrupt flag, you should re-enable
  454.   interrupts in a protected mode IRQ handler. This is because the interrupt
  455.   flag will have been cleared upon entry to the handler.
  456.  
  457.   When writing interrupt handlers, you must terminate them with an IRETD, not
  458. a simple IRET. For hardware IRQ handlers, you may want to make sure that any
  459. code and data that may be touched by the IRQ handler resides in low memory,
  460. below 1M. This memory is locked under DPMI, and will prevent having to swap
  461. from disk at interrupt time under DPMI hosts which support virtual memory. One
  462. other thing you should remember about IRQ handlers. IRQ 2 is really IRQ 9.
  463. Devices which say they use IRQ 2 are actually using IRQ 9. In real mode, the
  464. BIOS handler for IRQ 9 redirects it to the handler for IRQ 2. There is no such
  465. redirection done in protected mode. So if you wish to write a handler for
  466. IRQ 2 in protected mode, you must put it on IRQ 9. And remember to send the
  467. EOI to the second interrupt controller. The BIOS IRQ 9 handler does that, but
  468. you don't have the BIOS anymore.
  469.  
  470. 1.4 - Real mode callbacks:
  471. --------------------------
  472.  
  473.   Real mode callbacks allow code running in real mode to call protected mode
  474. procedures in a transparent manner. The real mode code thinks it is passing
  475. control to another real mode procedure. This is, in reality, a real mode
  476. callback. Which is basically a small routine which stores the values of the
  477. real mode registers in a structure, then switches to protected mode and passes
  478. control to a protected mode routine you specify.
  479.  
  480.   Callbacks are allocated and freed just like descriptors or memory. When
  481. allocating a callback, your code specifies the address of the protected mode
  482. routine that is to gain control when the real mode callback is called. You
  483. must also specify the selector:offset of a memory structure that is to recieve
  484. the contents of the registers in real mode. The format of this structure is
  485. the same as for INT 31h functions 0300h, 0301h, and 0302h. When the protected
  486. mode routine for a real mode callback gets control, interrupts will be
  487. disabled, and the following registers are defined:
  488.  
  489.   DS:ESI - selector:offset corresponding to real mode SS:SP
  490.   ES:EDI - selector:offset of real mode register data structure
  491.   SS:ESP - protecterd mode stack provided by PMODE or the DPMI host
  492.  
  493. The real mode register data structure has the following format:
  494.  
  495.   Offset  Length  Contents
  496.   00h     4       EDI
  497.   04h     4       ESI
  498.   08h     4       EBP
  499.   0ch     4       reserved, ignored
  500.   10h     4       EBX
  501.   14h     4       EDX
  502.   18h     4       ECX
  503.   1ch     4       EAX
  504.   20h     2       CPU status flags
  505.   22h     2       ES
  506.   24h     2       DS
  507.   26h     2       FS
  508.   28h     2       GS
  509.   2ah     2       IP, undefined
  510.   2ch     2       CS, undefined
  511.   2eh     2       SP
  512.   30h     2       SS
  513.  
  514.   All fields except the CS and IP are filled in with the contents of the real
  515. mode registers when the real mode callback got control. The protected mode
  516. callback procedure can extract its parameters from the register data structure
  517. and/or the real mode stack. Remember that the segment registers contain real
  518. mode segment addresses, not protected mode selectors.
  519.  
  520.   The protected mode callback procedure exits with an IRETD with the address
  521. of the real mode register data structure in ES:EDI. Information can be passed
  522. back to real mode by modifying the contents of the register data structure and
  523. the real mode stack. The protected mode callback routine is responsible for
  524. setting the correct address for the resumption of execution in real mode in
  525. the CS:IP fields of the register data structure. It is also responsible for
  526. updating the SS:SP fields in the register data structure to remove the address
  527. of the calling real mode routine from the real mode stack.
  528.  
  529.   The real mode register data structure and the DS selector used to map the
  530. real mode SS segment are static. This is not a problem if you leave interrupts
  531. disabled throughout the protected mode callback routine. But if you intend to
  532. re-enable interrupts, you must make sure you do not use the DS selector
  533. anymore. If you need to access the real mode stack after enabling interrupts,
  534. you must create an alias descriptor for the DS selector passed to your
  535. callback procedure. Or you can take other measures, but just remember that the
  536. original DS selector is no longer safe after enabling interrupts in a
  537. protected mode callback routine.
  538.  
  539.   Since the real mode register data structure is also static, you should take
  540. special care if you wish to enable interrupts in a callback. Since the data
  541. structure is needed for the exit from the callback, you can not simply
  542. discard it. You should make a copy of the data structure. You can then pass
  543. back the copy when you exit the callback procedure. The ES:EDI upon exit is
  544. not required to be the same as on entry.
  545.  
  546. 1.5 - PMODE specifics:
  547. ----------------------
  548.  
  549.   PMODE makes several variables public. These control certain things when
  550. running under VCPI, XMS, or a raw system. Under DPMI, these variables do
  551. absolutely nothing. The size of the low memory protected mode buffer required
  552. for _pm_init is directly affected by these variables. Thus, they must be set
  553. to the same values for the call to _pm_info and _pm_init. You should only
  554. modify these variables before switching into protected mode.
  555.  
  556. ) _pm_pagetables - This specifies the number of page tables you want to have
  557.   under VCPI. Each page table requires 4k and maps 4M of linear memory. Page
  558.   tables only define linear address space, not actual physical memory. The
  559.   amount of extended memory that will be available to your code will be the
  560.   lesser of linear and physical memory in the system. Setting a higher number
  561.   of page tables will not give you any more physical memory than is available
  562.   in the system, but it will give you more linear address space where physical
  563.   memory can be mapped. This helps reduce fragmentation of memory when
  564.   allocating extended memory blocks under VCPI. Never set this variable to 0,
  565.   since the first page table maps the low megabyte of real mode memory.
  566.  
  567. ) _pm_selectors - This is the total number of descriptors you want PMODE to
  568.   make available to your code for allocation. The range for this variable is
  569.   0 to about 8150. The actual max number of descriptors that can exist in the
  570.   global descriptor table, which is where descriptors under PMODE reside, is
  571.   8191. But some of these descriptors are used by PMODE. Also, DPMI may not
  572.   be able to provide quite as many as 8000 descriptors. Each descriptor takes
  573.   up 8 bytes of space in the low memory protected mode buffer.
  574.  
  575. ) _pm_callbacks - This is the number of real mode callbacks you want PMODE to
  576.   provide for allocation. Each callback takes up 19 bytes of space. You may
  577.   set this variable to 0.
  578.  
  579. ) _pm_rmstacklen - This is the size of the real mode stack, in paragraphs,
  580.   that is provided for IRQ and INT redirection to real mode. Also for INT 31h
  581.   functions 0300h, 0301h, and 0302h when the SS:SP field in the register
  582.   structure is zero.
  583.  
  584. ) _pm_rmstacks - This is the number of real mode stacks you want present in
  585.   case of nested calls to real mode. There must be at least one.
  586.  
  587. ) _pm_pmstacklen - This is the size of the protected mode stack, in
  588.   paragraphs, to provide for protected mode procedures which handle real mode
  589.   callbacks.
  590.  
  591. ) _pm_pmstacks - This is the number of protected mode stacks you want present
  592.   in case of nested callbacks. If your code is not going to be using real mode
  593.   callbacks, you may set this variable, along with _pm_pmstacklen and
  594.   _pm_callbacks, to zero.
  595.  
  596. ------------------------------------------------------------------------------
  597. 2 - Functions:
  598. --------------
  599.  
  600.   PMODE duplicates a subset of DPMI protected mode functions. These functions
  601. are available ONLY in protected through INT 31h. They provide descriptor
  602. services, extended memory services, interrupt services, translation services,
  603. and some other misc things. A function is called by setting AX to the function
  604. code, setting any other registers for the function, and executing an INT 31h.
  605. Upon return, the carry flag will be clear if the function was successful. If
  606. the carry flag is set, the function failed. In this case, an error code will
  607. be placed in AX. However, DPMI 0.9 will not return error codes, just the carry
  608. flag set on errors. All other registers are preserved unless otherwise stated.
  609.  
  610. 2.0 - Function 0000h - Allocate Descriptors:
  611. --------------------------------------------
  612.  
  613. Allocates one or more descriptors in the client's descriptor table. The
  614. descriptor(s) allocated must be initialized by the application with other
  615. function calls.
  616.  
  617. In:
  618.   AX     = 0000h
  619.   CX     = number of descriptors to allocate
  620.  
  621. Out:
  622.   if successful:
  623.   AX     = base selector
  624.  
  625.   if failed:
  626.   AX     = error code:
  627.            8011h - descriptor unavailable
  628.            8021h - invalid value (CX = 0) (VCPI/XMS/raw only)
  629.  
  630. Notes:
  631. ) If more that one descriptor was requested, the function returns a base
  632.   selector referencing the first of a contiguous array of descriptors. The
  633.   selector values for subsequent descriptors in the array can be calculated
  634.   by adding the value returned by INT 31h function 0003h.
  635.  
  636. ) The allocated descriptor(s) will be set to expand-up writeable data, with
  637.   the present bit set and a base and limit of zero. The privilege level of the
  638.   descriptor(s) will match the client's code segment privilege level,
  639.  
  640. 2.1 - Function 0001h - Free Descriptor:
  641. ---------------------------------------
  642.  
  643. Frees a descriptor.
  644.  
  645. In:
  646.   AX     = 0001h
  647.   BX     = selector for the descriptor to free
  648.  
  649. Out:
  650.   if failed:
  651.   AX     = error code:
  652.            8022h - invalid selector
  653.  
  654. Notes:
  655. ) Each descriptor allocated with INT 31h function 0000h must be freed
  656.   individually with the function. Even if it was previously allocated as part
  657.   of a contiguous array of descriptors.
  658.  
  659. ) Under DPMI 1.0/VCPI/XMS/raw, any segment registers which contain the
  660.   selector being freed are zeroed by this function.
  661.  
  662. 2.2 - Function 0003h - Get Selector Increment Value:
  663. ----------------------------------------------------
  664.  
  665. The Allocate Descriptors function (0000h) can allocate an array of contiguous
  666. descriptors, but only return a selector for the first descriptor. The value
  667. returned by this function can be used to calculate the selectors for
  668. subsequent descriptors in the array.
  669.  
  670. In:
  671.   AX     = 0003h
  672.  
  673. Out:
  674.   always successful:
  675.   AX     = selector increment value
  676.  
  677. Notes:
  678. ) The increment value is always a power of two.
  679.  
  680. 2.3 - Function 0006h - Get Segment Base Address:
  681. ------------------------------------------------
  682.  
  683. Returns the 32bit linear base address from the descriptor table for the
  684. specified segment.
  685.  
  686. In:
  687.   AX     = 0006h
  688.   BX     = selector
  689.  
  690. Out:
  691.   if successful:
  692.   CX:DX  = 32bit linear base address of segment
  693.  
  694.   if failed:
  695.   AX     = error code:
  696.            8022h - invalid selector
  697.  
  698. Notes:
  699. ) Client programs must use the LSL instruction to query the limit for a
  700.   descriptor.
  701.  
  702. 2.4 - Function 0007h - Set Segment Base Address:
  703. ------------------------------------------------
  704.  
  705. Sets the 32bit linear base address field in the descriptor for the specified
  706. segment.
  707.  
  708. In:
  709.   AX     = 0007h
  710.   BX     = selector
  711.   CX:DX  = 32bit linear base address of segment
  712.  
  713. Out:
  714.   if failed:
  715.   AX     = error code:
  716.            8022h - invalid selector
  717.            8025h - invalid linear address (changing the base would cause the
  718.                    descriptor to reference a linear address range outside that
  719.                    allowed for DPMI clients) (DPMI 1.0 only)
  720.  
  721. Notes:
  722. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  723.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  724.   but it is not guaranteed.
  725.  
  726. ) I hope you have enough sense not to try to modify your current CS or SS
  727.   descriptor.
  728.  
  729. 2.5 - Function 0008h - Set Segment Limit:
  730. -----------------------------------------
  731.  
  732. Sets the limit field in the descriptor for the specified segment.
  733.  
  734. In:
  735.   AX     = 0008h
  736.   BX     = selector
  737.   CX:DX  = 32bit segment limit
  738.  
  739. Out:
  740.   if failed:
  741.   AX     = error code:
  742.            8021h - invalid value (the limit is > 1M, but the low 12 bits are
  743.                    not set)
  744.            8022h - invalid selector
  745.            8025h - invalid linear address (changing the base would cause the
  746.                    descriptor to reference a linear address range outside that
  747.                    allowed for DPMI clients) (DPMI 1.0 only)
  748.  
  749. Notes:
  750. ) The value supplied to the function in CX:DX is the byte length of the
  751.   segment-1.
  752.  
  753. ) Segment limits greater than or equal to 1M must be page aligned. That is,
  754.   they must have the low 12 bits set.
  755.  
  756. ) This function has an implicit effect on the "G" bit in the segment's
  757.   descriptor.
  758.  
  759. ) Client programs must use the LSL instruction to query the limit for a
  760.   descriptor.
  761.  
  762. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  763.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  764.   but it is not guaranteed.
  765.  
  766. ) I hope you have enough sense not to try to modify your current CS or SS
  767.   descriptor.
  768.  
  769. 2.6 - Function 0009h - Set Descriptor Access Rights:
  770. ----------------------------------------------------
  771.  
  772. Modifies the access rights field in the descriptor for the specified segment.
  773.  
  774. In:
  775.   AX     = 0009h
  776.   BX     = selector
  777.   CX     = access rights/type word
  778.  
  779. Out:
  780.   if failed:
  781.   AX     = error code:
  782.            8021h - invalid value (access rights/type word invalid)
  783.            8022h - invalid selector
  784.            8025h - invalid linear address (changing the base would cause the
  785.                    descriptor to reference a linear address range outside that
  786.                    allowed for DPMI clients) (DPMI 1.0 only)
  787.  
  788. Notes:
  789. ) The access rights/type word passed to the function in CX has the following
  790.   format:
  791.  
  792.     Bit: 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  793.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  794.        | G |B/D| 0 | ? |       ?       | 1 |  DPL  | 1 |C/D|E/C|W/R| A |
  795.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  796.  
  797.     G   - 0=byte granular, 1=page granular
  798.     B/D - 0=default 16bit, 1=default 32bit
  799.     DPL - must be equal to caller's CPL
  800.     C/D - 0=data, 1=code
  801.     E/C - data: 0=expand-up, 1=expand-down
  802.           code: must be 0 (non-conforming)
  803.     W/R - data: 0=read, 1=read/write
  804.           code: must be 1 (readable)
  805.     A   - 0=not accessed, 1=accessed
  806.     0   - must be 0
  807.     1   - must be 1
  808.     ?   - ignored
  809.  
  810. ) Client programs should use the LAR instruction to examine the access rights
  811.   of a descriptor.
  812.  
  813. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  814.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  815.   but it is not guaranteed.
  816.  
  817. ) I hope you have enough sense not to try to modify your current CS or SS
  818.   descriptor.
  819.  
  820. 2.7 - Function 000Ah - Create Alias Descriptor:
  821. -----------------------------------------------
  822.  
  823. Creates a new data descriptor that has the same base and limit as the
  824. specified descriptor.
  825.  
  826. In:
  827.   AX     = 000ah
  828.   BX     = selector
  829.  
  830. Out:
  831.   if successful:
  832.   AX     = data selector (alias)
  833.  
  834.   if failed:
  835.   AX     = error code:
  836.            8011h - descriptor unavailable
  837.            8022h - invalid selector
  838.  
  839. Notes:
  840. ) The selector supplied to the function may be either a data descriptor or
  841.   a code descriptor. The alias descriptor created is always an expand-up
  842.   writeable data segment.
  843.  
  844. ) The descriptor alias returned by this function will not track changes to the
  845.   original descriptor.
  846.  
  847. 2.8 - Function 000Bh - Get Descriptor:
  848. --------------------------------------
  849.  
  850. Copies the descriptor table entry for the specified selector into an 8 byte
  851. buffer.
  852.  
  853. In:
  854.   AX     = 000bh
  855.   BX     = selector
  856.   ES:EDI = selector:offset of 8 byte buffer
  857.  
  858. Out:
  859.   if successful:
  860.   buffer pointed to by ES:EDI contains descriptor
  861.  
  862.   if failed:
  863.   AX     = error code:
  864.            8022h - invalid selector
  865.  
  866. 2.9 - Function 000Ch - Set Descriptor:
  867. --------------------------------------
  868.  
  869. Copies the contents of an 8 byte buffer into the descriptor for the specified
  870. selector.
  871.  
  872. In:
  873.   AX     = 000ch
  874.   BX     = selector
  875.   ES:EDI = selector:offset of 8 byte buffer containing descriptor
  876.  
  877. Out:
  878.   if failed:
  879.   AX     = error code:
  880.            8021h - invalid value (access rights/type word invalid)
  881.            8022h - invalid selector
  882.            8025h - invalid linear address (changing the base would cause the
  883.                    descriptor to reference a linear address range outside that
  884.                    allowed for DPMI clients) (DPMI 1.0 only)
  885.  
  886. ) The descriptors access rights/type word at offset 5 within the descriptor
  887.   follows the same format and restrictions as the access rights/type parameter
  888.   CX to the Set Descriptor Access Rights function (0009h).
  889.  
  890. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  891.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  892.   but it is not guaranteed.
  893.  
  894. ) I hope you have enough sense not to try to modify your current CS or SS
  895.   descriptor or the descriptor of the buffer.
  896.  
  897. 2.10 - Function 000Eh - Get Multiple Descriptors:
  898. -------------------------------------------------
  899.  
  900. Copies one or more descriptor table entries into a buffer.
  901.  
  902. In:
  903.   AX     = 000eh
  904.   CX     = number of descriptors to copy
  905.   ES:EDI = selector:offset of a buffer in the following format:
  906.  
  907.            Offset  Length  Contents
  908.            00h     2       Selector #1 (set by client)
  909.            02h     8       Descriptor #1 (returned by host)
  910.            0ah     2       Selector #2 (set by client)
  911.            0ch     8       Descriptor #2 (returned by host)
  912.            ...     ...     ...
  913.  
  914. Out:
  915.   if successful:
  916.   buffer contains copies of the descriptors for the specified selectors
  917.  
  918.   if failed:
  919.   AX     = error code:
  920.            8022h - invalid selector
  921.   CX     = number of descriptors successfully copied
  922.  
  923. Notes:
  924. ) If an error occurs because of an invalid selector or descriptor, the
  925.   function returns the number of descriptors which were successfully copied
  926.   in CX. All of the descriptors which were copied prior to the one that failed
  927.   are valid.
  928.  
  929. ) This function is not present under DPMI 0.9.
  930.  
  931. 2.11 - Function 000Fh - Set Multiple Descriptors:
  932. -------------------------------------------------
  933.  
  934. Copies one or more descriptors from a client buffer into the descriptor table.
  935.  
  936. In:
  937.   AX     = 000fh
  938.   CX     = number of descriptors to copy
  939.   ES:EDI = selector:offset of a buffer in the following format:
  940.  
  941.            Offset  Length  Contents
  942.            00h     2       Selector #1
  943.            02h     8       Descriptor #1
  944.            0ah     2       Selector #2
  945.            0ch     8       Descriptor #2
  946.            ...     ...     ...
  947.  
  948. Out:
  949.   if failed:
  950.   AX     = error code:
  951.            8021h - invalid value (access rights/type word invalid)
  952.            8022h - invalid selector
  953.            8025h - invalid linear address (changing the base would cause the
  954.                    descriptor to reference a linear address range outside that
  955.                    allowed for DPMI clients) (DPMI 1.0 only)
  956.   CX     = number of descriptors successfully copied
  957.  
  958. Notes:
  959. ) If an error occurs because of an invalid selector or descriptor, the
  960.   function returns the number of descriptors which were successfully copied in
  961.   CX. All of the descriptors which were copied prior to the one that failed
  962.   are valid.
  963.  
  964. ) The descriptors access rights/type word at offset 5 within the descriptor
  965.   follows the same format and restrictions as the access rights/type parameter
  966.   CX to the Set Descriptor Access Rights (0009h) function.
  967.  
  968. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains a selector
  969.   specified in the data structure will be reloaded. DPMI 0.9 may do this,
  970.   but it is not guaranteed.
  971.  
  972. ) I hope you have enough sense not to try to modify your current CS or SS
  973.   descriptor or the descriptor of the buffer.
  974.  
  975. ) This function is not present under DPMI 0.9.
  976.  
  977. 2.12 - Function 0200h - Get Real Mode Interrupt Vector:
  978. -------------------------------------------------------
  979.  
  980. Returns the real mode segment:offset for the specified interrupt vector.
  981.  
  982. In:
  983.   AX     = 0200h
  984.   BL     = interrupt number
  985.  
  986. Out:
  987.   always successful:
  988.   CX:DX  = segment:offset of real mode interrupt handler
  989.  
  990. Notes:
  991. ) The value returned in CX is a real mode segment address, not a protected
  992.   mode selector.
  993.  
  994. 2.13 - Function 0201h - Set Real Mode Interrupt Vector:
  995. -------------------------------------------------------
  996.  
  997. Sets the real mode segment:offset for the specified interrupt vector.
  998.  
  999. In:
  1000.   AX     = 0201h
  1001.   BL     = interrupt number
  1002.   CX:DX  = segment:offset of real mode interrupt handler
  1003.  
  1004. Notes:
  1005. ) The value passed in CX must be a real mode segment address, not a protected
  1006.   mode selector. Consequently, the interrupt handler must either reside in
  1007.   DOS memory (below the 1M boundary) or the client must allocate a real mode
  1008.   callback address.
  1009.  
  1010. 2.14 - Function 0204h - Get Protected Mode Interrupt Vector:
  1011. ------------------------------------------------------------
  1012.  
  1013. Returns the address of the current protected mode interrupt handler for the
  1014. specified interrupt.
  1015.  
  1016. In:
  1017.   AX     = 0204h
  1018.   BL     = interrupt number
  1019.  
  1020. Out:
  1021.   always successful:
  1022.   CX:EDX = selector:offset of protected mode interrupt handler
  1023.  
  1024. Notes:
  1025. ) The value returned in CX is a valid protected mode selector, not a real mode
  1026.   segment address.
  1027.  
  1028. 2.15 - Function 0205h - Set Protected Mode Interrupt Vector:
  1029. ------------------------------------------------------------
  1030.  
  1031. Sets the address of the protected mode interrupt handler for the specified
  1032. interrupt.
  1033.  
  1034. In:
  1035.   AX     = 0205h
  1036.   BL     = interrupt number
  1037.   CX:EDX = selector offset of protected mode interrupt handler
  1038.  
  1039. Out:
  1040.   if failed:
  1041.   AX     = error code:
  1042.            8022h - invalid selector
  1043.  
  1044. Notes:
  1045. ) The value passed in CX must be a valid protected mode selector, not a real
  1046.   mode segment address.
  1047.  
  1048. 2.16 - Function 0300h - Simulate Real Mode Interrupt:
  1049. -----------------------------------------------------
  1050.  
  1051. Simulates an interrupt in real mode. The function transfers control to the
  1052. address specified by the real mode interrupt vector. The real mode handler
  1053. must return by executing an IRET.
  1054.  
  1055. In:
  1056.   AX     = 0300h
  1057.   BL     = interrupt number
  1058.   BH     = must be 0
  1059.   CX     = number of words to copy from the protected mode stack to the real
  1060.            mode stack
  1061.   ES:EDI = selector:offset of real mode register data structure in the
  1062.            following format:
  1063.  
  1064.            Offset  Length  Contents
  1065.            00h     4       EDI
  1066.            04h     4       ESI
  1067.            08h     4       EBP
  1068.            0ch     4       reserved, ignored
  1069.            10h     4       EBX
  1070.            14h     4       EDX
  1071.            18h     4       ECX
  1072.            1ch     4       EAX
  1073.            20h     2       CPU status flags
  1074.            22h     2       ES
  1075.            24h     2       DS
  1076.            26h     2       FS
  1077.            28h     2       GS
  1078.            2ah     2       IP (reserved, ignored)
  1079.            2ch     2       CS (reserved, ignored)
  1080.            2eh     2       SP
  1081.            30h     2       SS
  1082.  
  1083. Out:
  1084.   if successful:
  1085.   ES:EDI = selector offset of modified real mode register data structure
  1086.  
  1087.   if failed:
  1088.   AX     = error code:
  1089.            8012h - linear memory unavailable (stack)
  1090.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1091.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1092.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1093.  
  1094. Notes:
  1095. ) The CS:IP in the real mode register data structure is ignored by this
  1096.   function. The appropriate interrupt handler will be called based on the
  1097.   value passed in BL.
  1098.  
  1099. ) If the SS:SP fields in the real mode register data structure are zero, a
  1100.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1101.   will be set to the specified values before the interrupt handler is called.
  1102.  
  1103. ) The flags specified in the real mode register data structure will be put on
  1104.   the real mode interrupt handler's IRET frame. The interrupt handler will be
  1105.   called with the interrupt and trace flags clear.
  1106.  
  1107. ) Values placed in the segment register positions of the data structure must
  1108.   be valid for real mode. That is, the values must be paragraph addresses, not
  1109.   protected mode selectors.
  1110.  
  1111. ) The target real mode handler must return with the stack in the same state
  1112.   as when it was called. This means that the real mode code may switch stacks
  1113.   while it is running, but must return on the same stack that it was called
  1114.   on and must return with an IRET.
  1115.  
  1116. ) When this function returns, the real mode register data structure will
  1117.   contain the values that were returned by the real mode interrupt handler.
  1118.   The CS:IP and SS:SP values will be unmodified in the data structure.
  1119.  
  1120. ) It is the caller's responsibility to remove any parameters that were pushed
  1121.   on the protected mode stack.
  1122.  
  1123. 2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame:
  1124. -----------------------------------------------------------------------
  1125.  
  1126. Simulates a FAR CALL to a real mode procedure. The called procedure must
  1127. return by executing a RETF instruction.
  1128.  
  1129. In:
  1130.   AX     = 0301h
  1131.   BH     = must be 0
  1132.   CX     = number of words to copy from the protected mode stack to the real
  1133.            mode stack
  1134.   ES:EDI = selector:offset of real mode register data structure in the
  1135.            following format:
  1136.  
  1137.            Offset  Length  Contents
  1138.            00h     4       EDI
  1139.            04h     4       ESI
  1140.            08h     4       EBP
  1141.            0ch     4       reserved, ignored
  1142.            10h     4       EBX
  1143.            14h     4       EDX
  1144.            18h     4       ECX
  1145.            1ch     4       EAX
  1146.            20h     2       CPU status flags
  1147.            22h     2       ES
  1148.            24h     2       DS
  1149.            26h     2       FS
  1150.            28h     2       GS
  1151.            2ah     2       IP
  1152.            2ch     2       CS
  1153.            2eh     2       SP
  1154.            30h     2       SS
  1155.  
  1156. Out:
  1157.   if successful:
  1158.   ES:EDI = selector offset of modified real mode register data structure
  1159.  
  1160.   if failed:
  1161.   AX     = error code:
  1162.            8012h - linear memory unavailable (stack)
  1163.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1164.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1165.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1166.  
  1167. Notes:
  1168. ) The CS:IP in the real mode register data structure specifies the address of
  1169.   the real mode procedure to call.
  1170.  
  1171. ) If the SS:SP fields in the real mode register data structure are zero, a
  1172.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1173.   will be set to the specified values before the procedure is called.
  1174.  
  1175. ) Values placed in the segment register positions of the data structure must
  1176.   be valid for real mode. That is, the values must be paragraph addresses, not
  1177.   protected mode selectors.
  1178.  
  1179. ) The target real mode procedure must return with the stack in the same state
  1180.   as when it was called. This means that the real mode code may switch stacks
  1181.   while it is running, but must return on the same stack that it was called
  1182.   on and must return with a RETF and should not clear the stack of any
  1183.   parameters that were passed to it on the stack.
  1184.  
  1185. ) When this function returns, the real mode register data structure will
  1186.   contain the values that were returned by the real mode procedure. The CS:IP
  1187.   and SS:SP values will be unmodified in the data structure.
  1188.  
  1189. ) It is the caller's responsibility to remove any parameters that were pushed
  1190.   on the protected mode stack.
  1191.  
  1192. 2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame:
  1193. -----------------------------------------------------------------
  1194.  
  1195. Simulates a FAR CALL with flags pushed on the stack to a real mode procedure.
  1196. The real mode procedure must return by executing an IRET instruction or a
  1197. RETF 2.
  1198.  
  1199. In:
  1200.   AX     = 0301h
  1201.   BH     = must be 0
  1202.   CX     = number of words to copy from the protected mode stack to the real
  1203.            mode stack
  1204.   ES:EDI = selector:offset of real mode register data structure in the
  1205.            following format:
  1206.  
  1207.            Offset  Length  Contents
  1208.            00h     4       EDI
  1209.            04h     4       ESI
  1210.            08h     4       EBP
  1211.            0ch     4       reserved, ignored
  1212.            10h     4       EBX
  1213.            14h     4       EDX
  1214.            18h     4       ECX
  1215.            1ch     4       EAX
  1216.            20h     2       CPU status flags
  1217.            22h     2       ES
  1218.            24h     2       DS
  1219.            26h     2       FS
  1220.            28h     2       GS
  1221.            2ah     2       IP
  1222.            2ch     2       CS
  1223.            2eh     2       SP
  1224.            30h     2       SS
  1225.  
  1226. Out:
  1227.   if successful:
  1228.   ES:EDI = selector offset of modified real mode register data structure
  1229.  
  1230.   if failed:
  1231.   AX     = error code:
  1232.            8012h - linear memory unavailable (stack)
  1233.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1234.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1235.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1236.  
  1237. Notes:
  1238. ) The CS:IP in the real mode register data structure specifies the address of
  1239.   the real mode procedure to call.
  1240.  
  1241. ) If the SS:SP fields in the real mode register data structure are zero, a
  1242.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1243.   will be set to the specified values before the procedure is called.
  1244.  
  1245. ) The flags specified in the real mode register data structure will be put on
  1246.   the real mode procedure's IRET frame. The procedure will be called with the
  1247.   interrupt and trace flags clear.
  1248.  
  1249. ) Values placed in the segment register positions of the data structure must
  1250.   be valid for real mode. That is, the values must be paragraph addresses, not
  1251.   protected mode selectors.
  1252.  
  1253. ) The target real mode procedure must return with the stack in the same state
  1254.   as when it was called. This means that the real mode code may switch stacks
  1255.   while it is running, but must return on the same stack that it was called
  1256.   on and must return with an IRET or discard the flags from the stack with a
  1257.   RETF 2 and should not clear the stack of any parameters that were passed to
  1258.   it on the stack.
  1259.  
  1260. ) When this function returns, the real mode register data structure will
  1261.   contain the values that were returned by the real mode procedure. The CS:IP
  1262.   and SS:SP values will be unmodified in the data structure.
  1263.  
  1264. ) It is the caller's responsibility to remove any parameters that were pushed
  1265.   on the protected mode stack.
  1266.  
  1267. 2.19 - Function 0303h - Allocate Real Mode Callback Address:
  1268. ------------------------------------------------------------
  1269.  
  1270. Returns a unique real mode segment:offset, known as a "real mode callback",
  1271. that will transfer control from real mode to a protected mode procedure.
  1272. Callback addresses obtained with this function can be passed by a protected
  1273. mode program to a real mode application, interrupt handler, device driver,
  1274. TSR, etc... so that the real mode program can call procedures within the
  1275. protected mode program.
  1276.  
  1277. In:
  1278.   AX     = 0303h
  1279.   DS:ESI = selector:offset of protected mode procedure to call
  1280.   ES:EDI = selector:offset of 32h byte buffer for real mode register data
  1281.            structure to be used when calling the callback routine.
  1282.  
  1283. Out:
  1284.   if successful:
  1285.   CX:DX  = segment:offset of real mode callback
  1286.  
  1287.   if failed:
  1288.   AX     = error code:
  1289.            8015h - callback unavailable
  1290.  
  1291. Notes:
  1292. ) A descriptor may be allocated for each callback to hold the real mode SS
  1293.   descriptor. Real mode callbacks are a limited system resource. A client
  1294.   should release a callback that it is no longer using.
  1295.  
  1296. 2.20 - Function 0304h - Free Real Mode Callback Address:
  1297. --------------------------------------------------------
  1298.  
  1299. Releases a real mode callback address that was previously allocated with the
  1300. Allocate Real Mode Callback Address function (0303h).
  1301.  
  1302. In:
  1303.   AX     = 0304h
  1304.   CX:DX  = segment:offset of real mode callback to be freed
  1305.  
  1306. Out:
  1307.   if failed:
  1308.   AX     = error code:
  1309.            8024h - invalid callback address
  1310.  
  1311. Notes:
  1312. ) Real mode callbacks are a limited system resource. A client should release
  1313.   any callback that it is no longer using.
  1314.  
  1315. 2.21 - Function 0305h - Get State Save/Restore Addresses:
  1316. ---------------------------------------------------------
  1317.  
  1318. Returns the address of two procedures used to save and restore the state of
  1319. the current task's registers in the mode (protected or real) which is not
  1320. currently executing.
  1321.  
  1322. In:
  1323.   AX     = 0305h
  1324.  
  1325. Out:
  1326.   always successful:
  1327.   AX     = size of buffer in bytes required to save state
  1328.   BX:CX  = segment:offset of real mode routine used to save/restore state
  1329.   SI:EDI = selector:offset of protected mode routine used to save/restore
  1330.            state
  1331.  
  1332. Notes:
  1333. ) The real mode segment:offset returned by this function should be called
  1334.   only in real mode to save/restore the state of the protected mode registers.
  1335.   The protected mode selector:offset returned by this function should be
  1336.   called only in protected mode to save/restore the state of the real mode
  1337.   registers.
  1338.  
  1339. ) Both of the state save/restore procedures are entered by a FAR CALL with the
  1340.   following parameters:
  1341.  
  1342.   AL       = 0 to save state
  1343.            = 1 to restore state
  1344.   ES:(E)DI = (selector or segment):offset of state buffer
  1345.  
  1346.   The state buffer must be at least as large as the value returned in AX by
  1347.   INT 31h function 0305h. The state save/restore procedures do not modify any
  1348.   registers. DI must be used for the buffer offset in real mode, EDI must be
  1349.   used in protected mode.
  1350.  
  1351. ) Some DPMI hosts and VCPI/XMS/raw will not require the state to be saved,
  1352.   indicating this by returning a buffer size of zero in AX. In such cases,
  1353.   that addresses returned by this function can still be called, although they
  1354.   will simply return without performing any useful function.
  1355.  
  1356. ) Clients do not need to call the state save/restore procedures before using
  1357.   INT 31h function 0300h, 0301h, or 0302h. The state save/restore procedures
  1358.   are provided for clients that use the raw mode switch services only.
  1359.  
  1360. 2.22 - Function 0306h - Get Raw Mode Switch Addresses:
  1361. ------------------------------------------------------
  1362.  
  1363. Returns addresses that can be called for low level mode switching.
  1364.  
  1365. In:
  1366.   AX     = 0306h
  1367.  
  1368. Out:
  1369.   always successful:
  1370.   BX:CX  = segment:offset of real to protected mode switch procedure
  1371.   SI:EDI = selector:offset of protected to real mode switch procedure
  1372.  
  1373. Notes:
  1374. ) The real mode segment:offset returned by this function should be called
  1375.   only in real mode to switch to protected mode. The protected mode
  1376.   selector:offset returned by this function should be called only in protected
  1377.   mode to switch to real mode.
  1378.  
  1379. ) The mode switch procedures are entered by a FAR JMP to the appropriate
  1380.   address with the following parameters:
  1381.  
  1382.   AX    = new DS
  1383.   CX    = new ES
  1384.   DX    = new SS
  1385.   (E)BX = new (E)SP
  1386.   SI    = new CS
  1387.   (E)DI = new (E)IP
  1388.  
  1389.   The processor is placed into the desired mode, and the DS, ES, SS, (E)SP,
  1390.   CS, and (E)IP registers are updated with the specific values. In other
  1391.   words, execution of the client continues in the requested mode at the
  1392.   address provided in registers SI:(E)DI. The values specified to be placed
  1393.   into the segment registers must be appropriate for the destination mode.
  1394.   That is, segment addresses for real mode, and selectors for protected mode.
  1395.  
  1396.   The values in EAX, EBX, ECX, EDX, ESI, and EDI after the mode switch are
  1397.   undefined. EBP will be preserved across the mode switch call so it can be
  1398.   used as a pointer. FS and GS will contain zero after the mode switch.
  1399.  
  1400.   If interrupts are disabled when the mode switch procedure is invoked, they
  1401.   will not be re-enabled by the host (even temporarily).
  1402.  
  1403. ) It is up to the client to save and restore the state of the task when using
  1404.   this function to switch modes. This requires the state save/restore
  1405.   procedures whose addresses can be obtained with INT 31h function 0305h.
  1406.  
  1407. 2.23 - Function 0400h - Get Version:
  1408. ------------------------------------
  1409.  
  1410. Returns the version of the DPMI Specification implemented by the DPMI host.
  1411. The client can use this information to determine what functions are available.
  1412.  
  1413. In:
  1414.   AX     = 0400h
  1415.  
  1416. Out:
  1417.   always successful:
  1418.   AH     = DPMI major version as a binary number (VCPI/XMS/raw returns 1)
  1419.   AL     = DPMI minor version as a binary number (VCPI/XMS/raw returns 0)
  1420.   BX     = flags:
  1421.            Bits    Significance
  1422.            0       0 = host is 16bit (PMODE never runs under one of these)
  1423.                    1 = host is 32bit
  1424.            1       0 = CPU returned to V86 mode for reflected interrupts
  1425.                    1 = CPU returned to real mode for reflected interrupts
  1426.            2       0 = virtual memory not supported
  1427.                    1 = virtual memory supported
  1428.            3-15    reserved
  1429.   CL     = processor type:
  1430.            03h = 80386
  1431.            04h = 80486
  1432.            05h = 80586
  1433.            06h-ffh = reserved
  1434.   DH     = current value of master PIC base interrupt (low 8 IRQs)
  1435.   DL     = current value of slave PIC base interrupt (high 8 IRQs)
  1436.  
  1437. Notes:
  1438. ) The major and minor version numbers are binary, not BCD. So a DPMI 0.9
  1439.   implementation would return AH as 0 and AL as 5ah (90).
  1440.  
  1441. 2.24 - Function 0500h - Get Free Memory Information:
  1442. ----------------------------------------------------
  1443.  
  1444. Returns information about the amount of available memory. Since DPMI clients
  1445. could be running in a multitasking environment, the information returned by
  1446. this function should be considered advisory.
  1447.  
  1448. In:
  1449.   AX     = 0500h
  1450.   ES:EDI = selector:offset of 48 byte buffer
  1451.  
  1452. Out:
  1453.   if successful:
  1454.   buffer is filled with the following information:
  1455.  
  1456.   if failed:
  1457.   AX     = error code:
  1458.            8010h - internal resource unavailable (stack) (XMS only)
  1459.  
  1460.   Offset  Length  Contents
  1461.   00h     4       Largest available free block in bytes
  1462.   04h     2ch     Other fields only supplied by DPMI
  1463.  
  1464. Notes:
  1465. ) Only the first field of the structure is guaranteed to contain a valid
  1466.   value. Any fields that are not supported by the host will be set to -1
  1467.   (0ffffffffh) to indicate that the information is not available.
  1468.  
  1469. 2.25 - Function 0501h - Allocate Memory Block:
  1470. ----------------------------------------------
  1471.  
  1472. Allocates a block of extended memory.
  1473.  
  1474. In:
  1475.   AX     = 0501h
  1476.   BX:CX  = size of block in bytes (must be non-zero)
  1477.  
  1478. Out:
  1479.   if successful:
  1480.   BX:CX  = linear address of allocated memory block
  1481.   SI:DI  = memory block handle (used to resize and free block)
  1482.  
  1483.   if failed:
  1484.   AX     = error code:
  1485.            8010h - internal resource unavailable (stack) (XMS only)
  1486.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1487.            8013h - physical memory unavailable
  1488.            8014h - backing store unavailable (DPMI 1.0 only)
  1489.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1490.            8021h - invalid value (BX:CX = 0)
  1491.  
  1492. Notes:
  1493. ) The allocated block is guaranteed to have at least paragraph alignment.
  1494.  
  1495. ) This function does not allocate any descriptors for the memory block. It is
  1496.   the responsibility of the client to allocate and initialize any descriptors
  1497.   needed to access the memory with additional function calls.
  1498.  
  1499. ) The allocations by this function could be paragraph, kilobyte, or page
  1500.   aligned. That is, the value you request could be rounded up to the next
  1501.   paragraph, kilobyte, or page value.
  1502.  
  1503. 2.26 - Function 0502h - Free Memory Block:
  1504. ------------------------------------------
  1505.  
  1506. Frees a memory block previously allocated with the Allocate Memory Block
  1507. function (0501h).
  1508.  
  1509. In:
  1510.   AX     = 0502h
  1511.   SI:DI  = memory block handle
  1512.  
  1513. Out:
  1514.   if failed:
  1515.   AX     = error code:
  1516.            8010h - internal resource unavailable (stack) (XMS only)
  1517.            8023h - invalid handle
  1518.  
  1519. Notes:
  1520. ) No descriptors are freed by this call. It is the client's responsibility to
  1521.   free any descriptors that it previously allocated to map the memory block.
  1522.   Descriptors should be freed before memory blocks.
  1523.  
  1524. 2.27 - Function 0503h - Resize Memory Block:
  1525. --------------------------------------------
  1526.  
  1527. Changes the size of a memory block previously allocated with the Allocate
  1528. Memory Block function (0501h).
  1529.  
  1530. In:
  1531.   AX     = 0503h
  1532.   BX:CX  = new size of block in bytes (must be non-zero)
  1533.   SI:DI  = memory block handle
  1534.  
  1535. Out:
  1536.   BX:CX  = new linear address of memory block
  1537.   SI:DI  = new memory block handle
  1538.  
  1539.   if failed:
  1540.   AX     = error code:
  1541.            8010h - internal resource unavailable (stack) (XMS only)
  1542.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1543.            8013h - physical memory unavailable
  1544.            8014h - backing store unavailable (DPMI 1.0 only)
  1545.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1546.            8021h - invalid value (BX:CX = 0)
  1547.            8023h - invalid handle
  1548.  
  1549. Notes:
  1550. ) After this function returns successfully, the previous handle for the memory
  1551.   block is invalid and should not be used anymore.
  1552.  
  1553. ) It is the client's responsibility to update any descriptors that map the
  1554.   memory block with the new linear address after resizing the block.
  1555.  
  1556. 2.28 - Function 050Ah - Get Memory Block Size and Base:
  1557. -------------------------------------------------------
  1558.  
  1559. Returns the size and base of a memory block that was previously allocated
  1560. with the Allocate Memory Block function (0501h).
  1561.  
  1562. In:
  1563.   AX     = 050ah
  1564.   SI:DI  = memory block handle
  1565.  
  1566. Out:
  1567.   if successful:
  1568.   BX:CX  = linear address of memory block
  1569.   SI:DI  = size of memory block (bytes)
  1570.  
  1571.   if failed:
  1572.   AX     = error code:
  1573.            8010h - internal resource unavailable (stack) (XMS only)
  1574.            8023h - invalid handle
  1575.  
  1576. Notes:
  1577. ) This function is not present under DPMI 0.9.
  1578.  
  1579. 2.29 - Function 0900h - Get and Disable Virtual Interrupt State:
  1580. ----------------------------------------------------------------
  1581.  
  1582. Disables the virtual interrupt flag and returns the previous state of it.
  1583.  
  1584. In:
  1585.   AX     = 0900h
  1586.  
  1587. Out:
  1588.   always successful:
  1589.   AL     = 0 if virtual interrupts were previously disabled
  1590.   AL     = 1 if virtual interrupts were previously enabled
  1591.  
  1592. Notes:
  1593. ) AH is not changed by this function. Therefore the previous state can be
  1594.   restored by simply executing another INT 31h.
  1595.  
  1596. ) A client that does not need to know the prior interrupt state can execute
  1597.   the CLI instruction rather than calling this function. The instruction may
  1598.   be trapped by a DPMI host and should be assumed to be very slow.
  1599.  
  1600. 2.30 - Function 0901h - Get and Enable Virtual Interrupt State:
  1601. ---------------------------------------------------------------
  1602.  
  1603. Enables the virtual interrupt flag and returns the previous state of it.
  1604.  
  1605. In:
  1606.   AX     = 0901h
  1607.  
  1608. Out:
  1609.   always successful:
  1610.   AL     = 0 if virtual interrupts were previously disabled
  1611.   AL     = 1 if virtual interrupts were previously enabled
  1612.  
  1613. Notes:
  1614. ) AH is not changed by this function. Therefore the previous state can be
  1615.   retstored by simply executing another INT 31h.
  1616.  
  1617. ) A client that does not need to know the prior interrupt state can execute
  1618.   the STI instruction rather than calling this function. The instruction may
  1619.   be trapped by a DPMI host and should be assumed to be very slow.
  1620.  
  1621. 2.31 - Function 0902h - Get Virtual Interrupt State:
  1622. ----------------------------------------------------
  1623.  
  1624. Returns the current state of the virtual interrupt flag.
  1625.  
  1626. In:
  1627.   AX     = 0902h
  1628.  
  1629. Out:
  1630.   always successful:
  1631.   AL     = 0 if virtual interrupts are disabled
  1632.   AL     = 1 if virtual interrupts are enabled
  1633.  
  1634. Notes:
  1635. ) This function should be used in preference to the PUSHF instruction to
  1636.   examine the interrupt flag, because the PUSHF instruction returns the
  1637.   physical interrupt flag rather than the virtualized interrupt flag. On some
  1638.   DPMI hosts, the physical interrupt flag will always be enabled, even when
  1639.   the hardware interrupts are not being passed through to the client.
  1640.  
  1641. 2.32 - Function FFFFh - Special Fluffy Magical Function:
  1642. --------------------------------------------------------
  1643.  
  1644. Does special fluffy magical things.
  1645.  
  1646. In:
  1647.   AX     = ffffh
  1648.  
  1649. Out:
  1650.   if successful:
  1651.   AX     = 1234h (normal fluffy magical number)
  1652.   BX     = 56ijh (special fluffy magical number)
  1653.   CX     = 89abh (nothing really special)
  1654.   DX     = cdefh (again, just a boring number)
  1655.   EX     = return value from beyond
  1656.   FX     = an acronym for 'effects'
  1657.   GX     = huh?
  1658.   HX     = size of special fluffy magical buffer
  1659.  
  1660.   if failed:
  1661.   AX     = error code:
  1662.            8001h - get a grip on reality!
  1663.  
  1664. Notes:
  1665. ) The special fluffy magical buffer must not exceed the special fluffy magical
  1666.   constant in size, which is defined in the special fluffy magical place.
  1667.  
  1668. ) Well, maybe it exists... Maybe if you try calling it many many many many
  1669.   many many many many times in a row it will succeed.
  1670.  
  1671. ------------------------------------------------------------------------------
  1672. 3 - Miscellenaous:
  1673. ------------------
  1674.  
  1675.   Some final things about PMODE, including some low level tech info if you are
  1676. just curious.
  1677.  
  1678. 3.0 - Glossary:
  1679. ---------------
  1680.  
  1681. Bottom up allocation - A method of extended memory allocation which relies on
  1682.   control blocks specifying the start of free extended memory. This is the
  1683.   VDISK extended memory allocation scheme.
  1684.  
  1685. Client - A program which uses DPMI INT 2fh and INT 31h services to run in
  1686.   protected mode.
  1687.  
  1688. CPL, Current Privilege Level - The privilege level of the currently executing
  1689.   code.
  1690.  
  1691. Descriptor - An 8 byte structure which defines a segment type, its base
  1692.   address and limit, and the type of access allowed to it.
  1693.  
  1694. DPL, Descriptor Privilege Level - The privilege level of a descriptor.
  1695.   Descriptor protection is based on certain rules of the CPL and DPL of a
  1696.   descriptor that code may want to access.
  1697.  
  1698. DPMI, DOS Protected Mode Interface - An interface for protected mode DOS
  1699.   programs to manage memory, interrupts, exceptions, debugging registers, and
  1700.   coprocessor emulation in a well behaved manner which allows them to coexist
  1701.   with other protected mode programs and operating systems.
  1702.  
  1703. Exception - An interrupt that occurs because of some violation of protection
  1704.   rules.
  1705.  
  1706. Extended memory - Memory which lies above the 1M boundary and can only be
  1707.   addressed in protected mode.
  1708.  
  1709. GDT, Global Descriptor Table - A descriptor table which can contain many types
  1710.   of descriptors besides the regular code and data descriptors. This can
  1711.   include TSS descriptors and LDT descriptors.
  1712.  
  1713. Host - A program which provides DPMI protected mode services.
  1714.  
  1715. IDT, Interrupt Descriptor Table - A descriptor table which contains the
  1716.   gate descriptors to the handlers for the 256 interrupts.
  1717.  
  1718. LDT, Local Descriptor Table - A descriptor table which usually contains all
  1719.   the descriptors of a particular task. Each task in a 386 multitasking system
  1720.   can have its own LDT whereas there is only one GDT for the entire system.
  1721.  
  1722. Linear memory - Address space rather than actual physical RAM of ROM.
  1723.  
  1724. Page - A 4k chunk of memory. The 80386 can map any 4k chunk of physical memory
  1725.   to any linear address. There are also some protection rules that can apply
  1726.   to pages, such as read-only, or privilege level checking on access.
  1727.  
  1728. Page Directory - Sort of a master page table which maps page tables instead of
  1729.   pages.
  1730.  
  1731. Page Table - A 4k table containing 1024 entries for pages. Each page table
  1732.   maps 4 megabytes of linear memory to physical memory.
  1733.  
  1734. Physical memory - The actual physical memory present in a system.
  1735.  
  1736. Privilege level - A numeric value representing the freedom of system access
  1737.   and how much protection applies to code. This value ranges from
  1738.   0 (most free (godlike)) to 3 (least free (lowly slave)).
  1739.  
  1740. RPL, Requestor Privilege Level - The privilege level code requests for a
  1741.   specific selector access. It is contained in the low two bits of the
  1742.   selector.
  1743.  
  1744. Segment - A specific linear chunk of memory. In real mode, segments are
  1745.   limited to the first megabyte of memory and are always 64k in length. In
  1746.   protected mode, a segment can start anywhere in the entire 4 gigabyte
  1747.   address space of the 80386 and can be that long.
  1748.  
  1749. Selector - An index in protected mode into a descriptor table. Selectors are
  1750.   used in place of segments in protected mode in the segment registers.
  1751.  
  1752. Top down allocation - A method of extended memory management which relies on
  1753.   the BIOS INT 15h function 88h. A program which needs to allocate extended
  1754.   memory will hook INT 15h and return a smaller extended memory size. The
  1755.   program is then free to use the memory between the previous top of extended
  1756.   memory and what it returns as the top of extended memory without worrying
  1757.   about other programs overwriting its extended memory.
  1758.  
  1759. TSS, Task State Segment - A special memory structure used in task switching
  1760.   and protection.
  1761.  
  1762. V86 mode - Actually it is protected mode, running at a privilege level of 3.
  1763.   Segment registers are used in the same manner as in real mode, with segment
  1764.   addresses rather than selectors. The advantage is that paging and other
  1765.   protected tasks can be active, which includes other V86 mode tasks. The
  1766.   disadvantage is that it is slower than real mode.
  1767.  
  1768. VCPI, Virtual Control Program Interface - The predecessor to DPMI. VCPI
  1769.   extends the EMS interface to allow DOS programs to run in protected mode
  1770.   in the presence of EMS emulators or other 80386 control programs.
  1771.  
  1772. Virtual memory - Extra memory beyond the actual physical memory present in a
  1773.   system. There is not really any more physical memory in the system, but an
  1774.   operating system or DPMI host can give that illusion by swapping the
  1775.   contents of physical memory to and from a disk and mapping that physical
  1776.   memory to different linear addresses.
  1777.  
  1778. XMS, eXtended Memory Specification - A handle based extended memory management
  1779.   interface.
  1780.  
  1781. 3.1 - Differences between modes:
  1782. --------------------------------
  1783.  
  1784. Some differences between DPMI, VCPI, XMS, and raw protected mode:
  1785.  
  1786. ) DPMI:
  1787.     Client descriptors reside in a LDT.
  1788.   VCPI/XMS/raw:
  1789.     Client descriptors reside in the GDT.
  1790.  
  1791. ) DPMI:
  1792.     Code runs at CPL 3. (I don't know of any DPMI that doesn't)
  1793.   VCPI/XMS/raw:
  1794.     Code runs at CPL 0. (Much faster)
  1795.  
  1796. ) DPMI/VCPI:
  1797.     Real mode calls are executed in V86 mode.
  1798. ) XMS/raw:
  1799.     Real mode calls are executed in real mode. (Much faster)
  1800.  
  1801. ) DPMI/VCPI:
  1802.     Paging is enabled.
  1803.   XMS/raw:
  1804.     Paging is disabled. (Not really very much faster, but what the hell)
  1805.  
  1806. ) DPMI:
  1807.     IRET(D) and POPF(D) may not affect the interrupt flag. PUSHF(D) may not
  1808.     store the interrupt flag.
  1809.   VCPI/XMS/raw:
  1810.     IRET(D) and POPF(D) affect the real interrupt flag. PUSHF(D) stores the
  1811.     real interrupt flag.
  1812.  
  1813. ) DPMI:
  1814.     INTs 1Ch, 23h, and 24h from real mode are sent to protected mode first.
  1815.     This means if a protected mode handler is installed for these interrupts,
  1816.     it will get control.
  1817. ) VCPI/XMS/raw:
  1818.     DPMI dox are not too clear on the method these interrupts are called in.
  1819.     Callbacks I would guess. But I am too lazy to investigate. And frankly, I
  1820.     don't give a shit. So the VCPI/XMS/raw kernel does not support this.
  1821.  
  1822. ) DPMI:
  1823.     Seperates exceptions from other low interrupts and IRQs. That is, an
  1824.     exception 8 would never erroneously go to the handler for IRQ 0.
  1825. ) VCPI/XMS/raw:
  1826.     Hey, exceptions are bad, you should not be getting them in the first
  1827.     place. Reprogramming the interrupt controllers or running the client code
  1828.     at a lower privilege is not worth the slowdown for me.
  1829.  
  1830. ) DPMI:
  1831.     Theoretically, DPMI may refuse a request to set a segment limit to 4G.
  1832.     I have not yet found a DPMI that will refuse this. They all do protection
  1833.     at the paging level. And a high limit is necessary for flat mode and
  1834.     negative offsets.
  1835. ) VCPI/XMS/raw:
  1836.     There is no protection, no segment limit or base address will ever be
  1837.     denied.
  1838.  
  1839. ) DPMI:
  1840.     Memory allocation is almost always page granular, but not necessarily.
  1841.   VCPI:
  1842.     Memory allocation is page granular (4k chunks).
  1843.   XMS:
  1844.     Memory allocation is kilobyte granular.
  1845.   raw:
  1846.     Memory allocation is paragraph granular.
  1847.  
  1848. ) DPMI/VCPI:
  1849.     Low memory linear addresses may or may not be the actual physical
  1850.     addresses. Extended memory addresses are almost sure not to be.
  1851.   XMS/raw:
  1852.     All linear addresses are physical addresses.
  1853.  
  1854. 3.2 - Notes:
  1855. ------------
  1856.  
  1857.   Here are some misc and low level technical details about PMODE and some
  1858. points I want to emphasize. Some of them may seem very obscure, with no real
  1859. need to list. But for the sake of thorough documentation, they are here:
  1860.  
  1861. ) In protected mode, ESP must always be the stack pointer. Meaning, even if
  1862.   using a 16bit stack segment, the high word of ESP MUST be 0.
  1863.  
  1864. ) When calling the raw mode switching routine to switch into protected mode,
  1865.   you must supply the full ESP and EIP. Even if the stack or code segments
  1866.   being switched to are 16bit.
  1867.  
  1868. ) If the call to init protected mode was from a segment other than PMODE_TEXT
  1869.   under DPMI, and a descriptor can not be allocated for that code segment,
  1870.   immediate termination results. But this should never happen. A DPMI host
  1871.   that can not supply even one descriptor to its protected mode clients defies
  1872.   logic. But for the sake of covering all possible screw-ups, this condition
  1873.   is checked for.
  1874.  
  1875. ) DPMI 1.0/VCPI/XMS/raw will reload any segment registers for which the
  1876.   descriptor is changed through an INT 31 function. DPMI 0.9 does not.
  1877.   (Actually it does, through pushing and then popping any segment registers
  1878.   it uses. But it is not guaranteed to reload any or all of them).
  1879.  
  1880. ) DPMI 1.0/VCPI/XMS/raw will zero any segment registers freed with INT 31
  1881.   function 0001h. DPMI 0.9 may or may not.
  1882.  
  1883. ) I dont know about DPMI with respect to reloading or freeing a selector which
  1884.   is currently loaded into SS, but the VCPI/XMS/raw system will not reload or
  1885.   zero SS. You should not be modifying your stack or code descriptor as you
  1886.   are using it. This could be bad, even if the INT 31 were handled through a
  1887.   task gate (which would be slow).
  1888.  
  1889. ) Remember that DPMI 0.9 does not return error codes as DPMI 1.0/VCPI/XMS/raw
  1890.   do.
  1891.  
  1892. ) Reasons for calls to real mode executing in actual real mode rather than
  1893.   V86 mode (XMS/raw):
  1894.   ) V86 call system can not be used under VCPI very successfully. (Yes, VCPI
  1895.     runs its real mode in V86. But VCPI MUST be in control in this case.)
  1896.   ) Real mode runs faster than V86 mode.
  1897.   ) INT 15h and XMS extended memory functions will work.
  1898.   ) Other protected mode programs that run DOS functions in real mode will
  1899.     work.
  1900.   ) It is faster to switch between protected/real mode than protected/V86.
  1901.  
  1902. ) Use LAR to find out the current CPL for setting descriptor access right.
  1903.  
  1904. ) You must always set the present bit when setting descriptor access rights.
  1905.  
  1906. ) Under the VCPI/XMS/raw system, the AVL bit of descriptors is used to keep
  1907.   track of free and used descriptors. The value you pass for this bit when
  1908.   setting descriptor access rights will be ignored.
  1909.  
  1910. ) When switching modes using the raw switching routines, make sure there is
  1911.   some space on both stacks (real and protected). Specific DPMI requirements
  1912.   may vary, but 64 bytes is enough for VCPI/XMS/raw.
  1913.  
  1914. ) In protected mode, remember to use IRETD, not IRET. When DPMI documentation
  1915.   refers to using IRET, it is actually referring to the 32bit version of the
  1916.   instruction under 32bit systems, which is IRETD.
  1917.  
  1918. ) Remember that free memory information is just advisory. A TSR or another
  1919.   task in a multitasking system might grab some memory in between a call to
  1920.   INT 31 function 0500h and INT 31 function 0501h, even if you disable
  1921.   interrupts.
  1922.  
  1923. ) The _pm_? variables are not checked for validity. So don't set them outside
  1924.   reasonable bounds. For example, don't ask for 20h real mode stacks of size
  1925.   1000h paragraphs. This is two megabytes of real mode stack space. This is
  1926.   way too much, considering that all real mode available low memory
  1927.   encompasses 640k.
  1928.  
  1929. ) You should allocate memory in large blocks. Memory space is subject to
  1930.   fragmentation. Although you can help the situation a little under VCPI by
  1931.   setting a high number of page tables. This will not increase the physical
  1932.   memory available, but it will increase the address space available to put
  1933.   that memory into linear chunks.
  1934.  
  1935. ) I tried to balance clean, well designed code, with size and speed. True,
  1936.   some things are not as absolutely optimal as they can be. But the source is
  1937.   right here. Very clean and commented. If you truly need those last ounces of
  1938.   speed, feel free to modify it (this does not free you from the obligation of
  1939.   crediting me for it).
  1940.  
  1941. ) I can not control what DPMI does. But under XMS/raw, code in protected mode
  1942.   runs at the fastest speed possible. That is, there is no privilege checking
  1943.   to get in the way. No exception will rip control away from sensitive
  1944.   instructions. Not even paging, with its memory references every time a page
  1945.   table entry is not found in the TLB. Under VCPI, all of this applies except
  1946.   the paging. Which really isn't that bad.
  1947.  
  1948. ) Under VCPI, free memory information is validated in function 0500h by
  1949.   actually allocating that memory and releasing it before passing the
  1950.   information to your program. This because under some multitasking systems,
  1951.   the VCPI function for getting the memory available may return information
  1952.   for the whole system. While the multitasking system may impose allocation
  1953.   limits on the specific task your code is part of.
  1954.  
  1955. ) Under VCPI/XMS/raw, INT 31 function 0500h will return only the first field
  1956.   of the buffer set. All the other fields will be set to 0ffffffffh.
  1957.  
  1958. ) Under VCPI/XMS/raw, an allocate descriptor INT 31 function 0000h called with
  1959.   CX = 0 will return error 8021h. DPMI dox dont state this, and I dont know if
  1960.   DPMI returns an error on CX = 0.
  1961.  
  1962. ) INT 31 functions 0300h, 0301h, and 0302h will always inform you if there is
  1963.   not enough real mode stack space. But and IRQ or INT redirection can not.
  1964.   In this case, the PC speaker will be turned on, and the machine will be
  1965.   hung. This is better than allowing it to overrun data below it with
  1966.   unpredictable results. And hey, I dont need no stinkin debug code cluttering
  1967.   up my nice and pretty extender. I just need it to tell me in case something
  1968.   like this happenes. If you want debug code, go and hack it in yourself.
  1969.  
  1970. ) DPMI dox dont state this, but the alias descriptor INT 31 function 000ah
  1971.   creates is always an expand-up and writeable data descriptor. No matter what
  1972.   type the source descriptor is.
  1973.  
  1974. ) You should limit yourself to allocating as few individual memory blocks as
  1975.   possible. Under XMS, there is usually a strict limit on how many blocks can
  1976.   be allocated (normally 32).
  1977.  
  1978. ) DPMI dox state that the field between EBP and EBX should be zero upon an
  1979.   INT 31 function 0300h, but is ignored by functions 0301h and 0302h. That is
  1980.   just a stupid typo, the field will be ignored by function 0300h.
  1981.  
  1982. ) Under XMS an extra 15 bytes will be allocated for possible aligning of the
  1983.   XMS memory block on a paragraph. Though an XMS block will probably already
  1984.   be aligned on at least a paragraph boundary, this is not defined in the XMS
  1985.   standard. And to keep the possibility of problems at nil, this is done.
  1986.  
  1987. ) Be aware that memory allocation functions under XMS use real mode calls and
  1988.   real mode stack space defined with _pm_rmstacklen and _pm_rmstacks. If there
  1989.   is not enough stack space for the call to the real mode XMS driver, error
  1990.   code 8010h (resource unavailable) will be returned.
  1991.  
  1992. ) If an XMS memory lock fails, which is used in memory allocation functions,
  1993.   error 8010h will be returned. A memory lock failure is not due to memory not
  1994.   being available. But rather, some internal XMS crap. But it should never
  1995.   happen anyway.
  1996.  
  1997. ) The raw system checks both INT 15h and the VDISK low to high extended memory
  1998.   allocation scheme to get its available extended memory area.
  1999.  
  2000. ) The raw system allocates extended memory on an as-needed basis from the top
  2001.   down. INT 15h function 88h is hooked and the total amount of memory
  2002.   allocated using the kernel function 0501h is subtracted from the amount of
  2003.   memory returned from the previous INT 15h handler. This is so that you can
  2004.   execute other protected mode programs from within your programs and they
  2005.   will have extended memory available (if you left any).
  2006.  
  2007. ) A protected mode IRQ handler or real mode callback must return on the same
  2008.   stack it was called with.
  2009.  
  2010. ) A real mode routine called with functions 0300h, 0301h, or 0302h must return
  2011.   on the same stack it was called with.
  2012.  
  2013. ) You should make no assumptions about the low memory protected mode data area
  2014.   needed by PMODE. It can range from very small to very large. And if a DPMI
  2015.   host is present, it is unpredictable.
  2016.  
  2017. ) Make sure you do not access, read or write, extended memory outside the
  2018.   blocks you allocate. Even if there is no physical memory there, you will
  2019.   probably get exceptions under DPMI/VCPI.
  2020.  
  2021. ) When setting descriptor access rights, remember that the B bit of stack
  2022.   descriptors determines whether PUSHes and POPs use SP (B=0) or ESP (B=1).
  2023.  
  2024. ) If you enable interrupts in a callback, you MUST assume DS is no longer
  2025.   valid. Even if you are sure your callback will not be re-entered. This is
  2026.   because PMODE uses the same DS selector for ALL real mode callbacks.
  2027.  
  2028. ) The reserved field between EBP and EBX in the register structure used during
  2029.   a callback is used by PMODE to preserve the high word of ESP for real mode.
  2030.  
  2031. ------------------------------------------------------------------------------
  2032. 3.3 - Final word:
  2033. -----------------
  2034.  
  2035.   I like this latest PMODE a lot. For an extender, it is clean, solid, fast,
  2036. and small. It is not limited to assembly code. It does not need control at
  2037. startup, but may be initialized at any time. It can be turned into basically
  2038. any type of extender. It can work with high level languages. You will probably
  2039. also like it because it is free, and the source code is provided. The DPMI
  2040. interface assures portability and long life. Enjoy protected mode, and
  2041. remember the credits.
  2042.  
  2043.   If you really really really really must contact me, try tran@phantom.com.
  2044. I do not guarantee a response, so don't get pissed off if you don't get one.
  2045.  
  2046.                                                 L8r...
  2047.                                                 Tran...
  2048.  
  2049.